"""扫描任务Celery任务"""
from typing import Dict, Any
from celery import Task
from sqlalchemy.orm import Session

from app.celery_app import celery_app
from app.database import SessionLocal
from app.scanners.registry import ScanExecutorRegistry
from app.scanners.base import ScanContext, ScanException
from app.services.scan_record_service import ScanRecordService
from app.services.issue_service import IssueService
from app.models.scan_record import ScanRecord
from app.models.issue import Issue
from app.models.scan_issue_extension import ScanIssueExtension
from app.utils.logger import logger


class ScanTask(Task):
    """扫描任务基类，支持进度更新"""
    
    def on_success(self, retval, task_id, args, kwargs):
        """任务成功回调"""
        logger.info("Scan task completed", task_id=task_id, record_id=args[0] if args else None)
    
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        """任务失败回调"""
        logger.error("Scan task failed", task_id=task_id, error=str(exc), record_id=args[0] if args else None)


@celery_app.task(bind=True, base=ScanTask, name="scan_task")
def scan_task(self, scan_record_id: int, task_id: int, task_type: str, branch: str, scan_params: Dict[str, Any], created_by: str = None):
    """
    执行扫描任务
    
    Args:
        scan_record_id: 扫描记录ID
        task_id: 任务ID
        task_type: 任务类型
        branch: 扫描分支
        scan_params: 扫描参数
        created_by: 创建人
        
    Returns:
        Dict: 扫描结果摘要
    """
    db: Session = SessionLocal()
    
    try:
        # 更新扫描记录状态为运行中
        record_service = ScanRecordService(db)
        record = record_service.get_by_id(scan_record_id)
        if not record:
            raise ValueError(f"扫描记录 {scan_record_id} 不存在")
        
        record.status = "running"
        db.commit()
        
        logger.info("Starting scan", record_id=scan_record_id, task_type=task_type, branch=branch)
        
        # 创建扫描上下文
        context = ScanContext(
            scan_record_id=scan_record_id,
            task_id=task_id,
            task_type=task_type,
            branch=branch,
            scan_params=scan_params,
            created_by=created_by,
        )
        
        # 获取扫描执行器
        executor = ScanExecutorRegistry.create_executor(task_type)
        if not executor:
            raise ValueError(f"未找到任务类型 {task_type} 的执行器")
        
        # 验证参数
        if not executor.validate_params(scan_params):
            raise ValueError(f"扫描参数验证失败: {scan_params}")
        
        # 执行扫描
        try:
            scan_result = executor.execute_scan(context)
        except ScanException as e:
            logger.error("Scan execution failed", record_id=scan_record_id, error=str(e))
            record.status = "failed"
            db.commit()
            raise
        
        # 保存扫描结果
        _save_scan_result(db, scan_record_id, scan_result, task_id)
        
        # 更新扫描记录状态
        record.status = "success"
        record.issue_count = len(scan_result.issues)
        record.unconfirmed_count = len(scan_result.issues)
        db.commit()
        
        logger.info("Scan completed", record_id=scan_record_id, issue_count=len(scan_result.issues))
        
        return {
            "scan_record_id": scan_record_id,
            "status": "success",
            "issue_count": len(scan_result.issues),
            "summary": scan_result.summary,
        }
        
    except Exception as e:
        logger.error("Scan task error", record_id=scan_record_id, error=str(e), exc_info=True)
        
        # 更新扫描记录状态为失败
        if record:
            record.status = "failed"
            db.commit()
        
        raise
    finally:
        db.close()


def _save_scan_result(db: Session, scan_record_id: int, scan_result, task_id: int, executor):
    """
    保存扫描结果到数据库
    
    Args:
        db: 数据库会话
        scan_record_id: 扫描记录ID
        scan_result: 扫描结果
        task_id: 任务ID
    """
    issue_service = IssueService(db)
    
    # 批量创建问题
    for idx, issue_data in enumerate(scan_result.issues, 1):
        # 生成问题编号
        issue_number = f"Q-{scan_record_id:06d}-{idx:04d}"
        
        # 创建问题
        issue = Issue(
            record_id=scan_record_id,
            issue_number=issue_number,
            rule_name=issue_data.get("rule_name", "未知规则"),
            level=issue_data.get("level", "info"),
            file_path=issue_data.get("file_path", ""),
            line_number=issue_data.get("line_number"),
            description=issue_data.get("description", ""),
            code_snippet=issue_data.get("code_snippet"),
        )
        db.add(issue)
        db.flush()
        
        # 保存扩展字段数据
        for key, value in issue_data.items():
            # 跳过基础字段
            if key in ["rule_name", "level", "file_path", "line_number", "description", "code_snippet"]:
                continue
            
            # 检查字段是否在支持的扩展字段列表中
            supported_extensions = executor.get_supported_extensions()
            if supported_extensions and key not in supported_extensions:
                continue
            
            # 保存为扩展字段（支持结构化数据）
            if isinstance(value, (dict, list)):
                field_value = value
            else:
                field_value = {"value": value}
            
            extension = ScanIssueExtension(
                issue_id=issue.id,
                field_name=key,
                field_value=field_value,
            )
            db.add(extension)
    
    db.commit()

